import { select, selectAll } from 'd3-selection'
import mitter from '@/mitt'
import { getTargetDataById, recursiveTreeValue, debounce } from '../utils'
import { getTopicNodeRect } from '../utils/size'
import { isRectangleInside } from '../utils/math'
import summaryLineShape from '../summary-line'
import topicShape from '../shape'
import { rc, summaryRoughOptions, summaryNoRoughOptions } from '../graph/drawSummary'

let summaryControlName = null // 当前概要控制节点class类名
let summaryBrothers = [] // 概要包括的节点集
let summaryArea = null // 概要可拖动区域
let selectCombinationId = null // 当前概要节点id
let combinationIds = []
let currentInsertSummaryId = null
let currentSummarydata = null

/**
 * 鼠标移入概要信息展示拖动控制节点以及概要范围矩形绘制
 */
export function summaryHandlerControllerDraw (parentId, _event, _this) {
  const combinationId = parentId || select(_this).datum().parentId
  if (select(`#summary-path-${combinationId}`).select('.select-target-summary').empty()) {
    select(`#summary-path-${combinationId}`)
      .select('.summary-highlight-border')
      .attr('stroke', 'rgb(46,189,255)')
      .attr('stroke-dasharray', function () {
        return `0 ${select(this).node().getTotalLength()}`
      })
      .transition()
      .duration(300)
      .attr('stroke-dasharray', function () {
        return `${select(this).node().getTotalLength()} 0`
      })
    const ids = combinationId.split('-')
    const sourceId = ids[0]
    const { x, y, width, height, upArea, downArea, direction } = select(`#summary-path-${combinationId} .summary-data-topic`).datum()
    select(`#summary-path-${combinationId}`)
      .select('.summary-data-topic')
      .append('rect')
      .attr('class', 'select-target-summary')
      .attr('x', x)
      .attr('y', y)
      .attr('width', width)
      .attr('height', height)
      .attr('stroke-width', 2)
      .attr('stroke', 'rgb(46,189,255)')
      .attr('rx', 4)
      .attr('ry', 4)
      .attr('fill', 'none')
      .attr('stroke-dasharray', function () {
        return `0 ${select(this).node().getTotalLength()}`
      })
      .transition()
      .duration(300)
      .attr('stroke-dasharray', function () {
        return `${select(this).node().getTotalLength()} 0`
      })
    select(`#summary-path-${combinationId}`)
      .select('.summary-data-topic')
      .selectAll('.control-point')
      .data(direction !== 'bottom' ? ['up', 'down'] : ['left', 'right'])
      .enter()
      .append('rect')
      .attr('class', d => `control-point ${d}`)
      .attr('x', (_d, idx) => direction !== 'bottom' ? x + width / 2 - 4 : (idx === 0 ? x - 4 : x + width - 4))
      .attr('y', (_d, idx) => direction !== 'bottom' ? (idx === 0 ? y - 4 : y + height - 4) : y + height / 2 - 4)
      .attr('width', 8)
      .attr('height', 8)
      .attr('stroke-width', 2)
      .attr('stroke', 'rgb(46,189,255)')
      .attr('fill', '#fff')
      .attr('opacity', 0)
      .on('mousedown', function (event) {
        event.stopPropagation()
        summaryControlName = select(this).attr('class')
        const sourcedata = select(`#${sourceId}`).datum()
        summaryBrothers = sourcedata.parent.children
        summaryArea = {
          upArea,
          downArea
        }
      })
  }
}

export function summaryControllerMove (svg, event, eventTransform) {
  if (summaryControlName) {
    if (['up', 'down'].includes(summaryControlName.split(' ')[1])) {
      summaryControlVerticalMove(event, eventTransform)
      svg.classed('n-resize', true)
    } else if (['left', 'right'].includes(summaryControlName.split(' ')[1])) {
      summaryControlHorizontalMove(event, eventTransform)
      svg.classed('e-resize', true)
    }
  }
}

/**
 * 概要控制点竖直方向上拖动绘制最新概要区域
 * @param {*} svg
 * @param {*} event
 * @param {*} eventTransform
 * @returns
 */
export function summaryControlVerticalMove (event, eventTransform) {
  const y = event.movementY / eventTransform.k
  const pageY = event.pageY
  const targetEle = select('.mind-map-summarybox .select-target-summary')
  const height = Number(targetEle.attr('height'))
  const oldY = Number(targetEle.attr('y'))
  const controlEle = select(`.${summaryControlName.split(' ')[1]}`)
  const controlEleY = controlEle.node().getBoundingClientRect().y
  const controlY = Number(controlEle.attr('y'))
  // 鼠标y坐标不在区域y坐标区间内不执行拖动
  if ((y < 0 && pageY > controlEleY) || (y > 0 && pageY < controlEleY)) return
  const idx = pageY > controlEleY ? 1 : 0
  if (summaryControlName.includes('down')) {
    if ((height + y + oldY <= summaryArea.downArea[0]) || ((height + y + oldY >= summaryArea.downArea[1]))) {
      targetEle.attr('height', summaryArea.downArea[idx] - oldY)
      controlEle.attr('y', summaryArea.downArea[idx] - 4)
      return
    }
    targetEle.attr('height', height + y)
    controlEle.attr('y', controlY + y)
  } else if (summaryControlName.includes('up')) {
    if ((oldY + y <= summaryArea.upArea[0]) || (oldY + y >= summaryArea.upArea[1])) {
      targetEle.attr('y', summaryArea.upArea[idx])
      targetEle.attr('height', height - summaryArea.upArea[idx] + oldY)
      controlEle.attr('y', controlY + summaryArea.upArea[idx] - oldY)
      return
    }
    targetEle.attr('y', oldY + y)
    targetEle.attr('height', height - y)
    controlEle.attr('y', controlY + y)
  }
}

/**
 * 概要控制点水平方向上拖动绘制最新概要区域
 * @param {*} svg
 * @param {*} event
 * @param {*} eventTransform
 * @returns
 */
export function summaryControlHorizontalMove (event, eventTransform) {
  const x = event.movementX / eventTransform.k
  const pageX = event.pageX
  const targetEle = select('.mind-map-summarybox .select-target-summary')
  const width = Number(targetEle.attr('width'))
  const oldX = Number(targetEle.attr('x'))
  const controlEle = select(`.${summaryControlName.split(' ')[1]}`)
  const controlEleX = controlEle.node().getBoundingClientRect().x
  const controlX = Number(controlEle.attr('x'))
  // 鼠标x坐标不在区域x坐标区间内不执行拖动
  if ((x < 0 && pageX > controlEleX) || (x > 0 && pageX < controlEleX)) return
  const idx = pageX > controlEleX ? 1 : 0
  if (summaryControlName.includes('right')) {
    if ((width + x + oldX <= summaryArea.downArea[0]) || ((width + x + oldX >= summaryArea.downArea[1]))) {
      targetEle.attr('width', summaryArea.downArea[idx] - oldX)
      controlEle.attr('x', summaryArea.downArea[idx] - 4)
      return
    }
    targetEle.attr('width', width + x)
    controlEle.attr('x', controlX + x)
  } else if (summaryControlName.includes('left')) {
    if ((oldX + x <= summaryArea.upArea[0]) || (oldX + x >= summaryArea.upArea[1])) {
      targetEle.attr('x', summaryArea.upArea[idx])
      targetEle.attr('width', width - summaryArea.upArea[idx] + oldX)
      controlEle.attr('x', controlX + summaryArea.upArea[idx] - oldX)
      return
    }
    targetEle.attr('x', oldX + x)
    targetEle.attr('width', width - x)
    controlEle.attr('x', controlX + x)
  }
}

/**
 * 概要控制点移动后抬起的一瞬间获取被概要区域包围的所有兄弟节点
 */
export function moveSummaryControlEnd (root, callback) {
  if (!summaryControlName) return
  const vertical = ['up', 'down'].includes(summaryControlName.split(' ')[1])
  const summaryLineArea = select('.select-target-summary')
  const sourceRect = {
    x: vertical ? -99999 : Number(summaryLineArea.attr('x')),
    y: vertical ? Number(summaryLineArea.attr('y')) : -99999,
    width: vertical ? 99999 * 2 : Number(summaryLineArea.attr('width')),
    height: vertical ? Number(summaryLineArea.attr('height')) : 99999 * 2
  }
  const cacheIds = []
  for (let i = 0; i < summaryBrothers.length; i++) {
    if (isRectangleInside(sourceRect, summaryBrothers[i])) {
      cacheIds.push(summaryBrothers[i].data._id)
    }
  }
  combinationIds = selectCombinationId.split('-')
  if (combinationIds[0] === cacheIds[0]) {
    const target = getTargetDataById(root, combinationIds[0])
    const targetSummarys = target.targetSummarys
    if (cacheIds[cacheIds.length - 1] !== combinationIds[1]) {
      const summary = targetSummarys.find(o => o.id === combinationIds[1])
      const hasExist = targetSummarys.findIndex(o => o.id === cacheIds[cacheIds.length - 1])
      if (hasExist > -1) {
        targetSummarys.splice(hasExist, 1)
      }
      summary.id = cacheIds[cacheIds.length - 1]
    }
  } else {
    const target = getTargetDataById(root, combinationIds[0])
    const idx = target.targetSummarys.findIndex(o => o.id === combinationIds[1])
    const { text, style } = target.targetSummarys[idx]
    if (idx > -1) {
      target.targetSummarys.splice(idx, 1)
    }
    const newSource = getTargetDataById(root, cacheIds[0])
    const summary = (newSource.targetSummarys || []).find(o => o.id === cacheIds[cacheIds.length - 1])
    if (!summary) {
      newSource.targetSummarys = [...(newSource.targetSummarys || []), {
        id: cacheIds[cacheIds.length - 1],
        text,
        style
      }]
    }
  }
  summaryControlName = false
  currentInsertSummaryId = null
  callback && callback()
}

/**
 * 更新概要节点内容
 * @param {*} root
 * @param {*} value
 */
export function updateSummaryText (root, value) {
  const ids = selectCombinationId.split('-')
  const target = getTargetDataById(root, ids[0])
  const summary = target.targetSummarys.find(o => o.id === ids[1])
  summary.text = value
}

/**
 * 概要节点点击
 * @param {*} summaryId
 * @param {*} event
 * @param {*} _this
 */
export function summaryNodeHandleClick (summaryId, event, _this) {
  event && event.stopPropagation()
  const id = summaryId || select(_this).datum().parentId
  currentSummarydata = select(`#summary-path-${id} .summary-data-topic`).datum()
  selectAll('.mind-map-summarybox .summary-data-topic')
    .filter(n => n.parentId !== id)
    .classed('active-summary-node', false)
    .selectAll('.select-target-summary, .control-point')
    .remove()
  selectAll('.mind-map-summarybox .summary-data-topic')
    .filter(n => n.parentId !== id)
    .select('.summary-highlight-border')
    .attr('stroke', 'none')
  select(`#summary-path-${id}`)
    .select('.summary-data-topic')
    .classed('active-summary-node', true)
    .selectAll('.control-point')
    .attr('opacity', 1)
  selectCombinationId = id
  mitter.emit('get-summary-style', currentSummarydata.style)
}

/**
 * 插入指定主题的概要信息
 * @param {*} root
 * @param {*} currnentNode
 * @param {*} callback
 * @returns
 */
export function handleInsertSummary (root, currnentNode) {
  const targetSummarys = currnentNode.data.targetSummarys
  const currentId = currnentNode.data._id
  if (!targetSummarys?.length) {
    currentInsertSummaryId = `${currentId}-${currentId}`
    recursiveTreeValue(root, currentId, 'targetSummarys', [{ id: currentId, text: '概要' }])
    return currentInsertSummaryId
  } else {
    if (!targetSummarys.find(o => o.id === currentId)) {
      currentInsertSummaryId = `${currentId}-${currentId}`
      targetSummarys.push({ id: currentId, text: '概要' })
      recursiveTreeValue(root, currentId, 'targetSummarys', targetSummarys.map(o => ({ id: o.id, text: o.text })))
      return currentInsertSummaryId
    }
    summaryHandlerControllerDraw(`${currentId}-${currentId}`)
    summaryNodeHandleClick(`${currentId}-${currentId}`)
  }
}

/**
 * 删除概要节点
 * @param {*} root
 * @param {*} callback
 * @returns
 */
export function handleDeleteSummary (root, callback) {
  if (!selectCombinationId) return
  const nodeIds = selectCombinationId.split('-')
  const target = getTargetDataById(root, nodeIds[0])
  const targetSummarys = target.targetSummarys
  const idx = targetSummarys.findIndex(o => o.id === nodeIds[1])
  if (idx > -1) {
    targetSummarys.splice(idx, 1)
    callback && callback()
  }
  currentSummarydata = null
  mitter.emit('get-summary-style', null)
}

/**
 * 清除概要节点高亮状态
 * @param {*} callback
 */
export function removeSummaryNodeHighLight () {
  selectAll('.mind-map-summarybox .summary-data-topic')
    .classed('active-summary-node', false)
    .selectAll('.select-target-summary, .control-point')
    .remove()
  selectAll('.mind-map-summarybox .summary-data-topic')
    .select('.summary-highlight-border')
    .attr('stroke', 'none')
  selectCombinationId = null
  currentInsertSummaryId = null
  currentSummarydata = null
  mitter.emit('get-summary-style', null)
}

export function summaryHandlerMouseLeave (_event, _this) {
  if (!select(_this).classed('active-summary-node')) {
    select(_this)
      .classed('active-summary-node', false)
      .select('.summary-highlight-border')
      .attr('stroke', 'none')
    select(_this)
      .selectAll('.select-target-summary, .control-point')
      .remove()
  }
}

/**
 * 概要样式更新
 * @param {*} styleName
 * @param {*} styleValue
 * @param {*} root
 * @param {*} callback
 */
export function updateSummaryStyle (styleName, styleValue, root, callback) {
  const {
    direction,
    forwardDirection,
    style,
    startX,
    startY,
    minX,
    minY,
    maxX,
    maxY,
    unit,
    text,
    centerPosition,
    highLightSummarySpacing,
    highLightTopicSpacing
  } = currentSummarydata
  const horizontal = ['left', 'right'].includes(direction)
  const summaryNode = select(`#summary-path-${selectCombinationId}`)
  if (styleName === 'lineColor') {
    summaryNode.select('.summary-line-path path').attr('stroke', styleValue)
  } else if (styleName === 'topicStrokeColor') {
    summaryNode.select('.summary-topic-path path:last-child').attr('stroke', styleValue)
  } else if (styleName === 'topicFill') {
    const isRough = style.isRough
    summaryNode.select('.summary-topic-path path:first-child').attr(isRough ? 'stroke' : 'fill', styleValue)
  } else if (styleName === 'textColor') {
    summaryNode.select('foreignObject').select('p').style('color', styleValue)
  } else if (['lineShape', 'topicShape', 'isRough', 'fontSize', 'fontFamily'].includes(styleName)) {
    const topicSizeOptions = {
      text: text,
      fontWeight: 'bold',
      maxWidth: '620px',
      shape: styleName === 'topicShape' ? styleValue : style.topicShape,
      fontSize: styleName === 'fontSize' ? styleValue : style.fontSize,
      fontFamily: styleName === 'fontFamily' ? styleValue : style.fontFamily,
      lineShape: styleName === 'lineShape' ? styleValue : style.lineShape,
      isRough: styleName === 'isRough' ? styleValue : style.isRough
    }
    const { width, height } = getTopicNodeRect(topicSizeOptions)
    const shapeGetPadding = topicShape[topicSizeOptions.shape].shapeGetPadding
    const { paddingT = 6, paddingL = 10 } = shapeGetPadding ? shapeGetPadding(width, height, 10, 10) : {}
    const [newSummaryWidth, newSummaryHeight] = [width + paddingL * 2, height + paddingT * 2]
    const newRectX = horizontal
      ? centerPosition.x + highLightTopicSpacing * 2 * unit - (forwardDirection ? 0 : newSummaryWidth)
      : centerPosition.x - newSummaryWidth / 2
    const newRectY = horizontal
      ? centerPosition.y - newSummaryHeight / 2
      : centerPosition.y + highLightTopicSpacing * 2 * unit - (forwardDirection ? 0 : newSummaryHeight)
    summaryNode.select('foreignObject')
      .attr('x', () => {
        return horizontal
          ? centerPosition.x + (highLightTopicSpacing * 2 + paddingL) * unit - (forwardDirection ? 0 : newSummaryWidth - paddingL * 2)
          : centerPosition.x - newSummaryWidth / 2 + paddingL
      })
      .attr('y', () => {
        return horizontal
          ? centerPosition.y - newSummaryHeight / 2 + paddingT
          : centerPosition.y + (highLightTopicSpacing * 2 + paddingT) * unit - (forwardDirection ? 0 : newSummaryHeight - paddingT * 2)
      })
      .attr('width', newSummaryWidth - paddingL * 2)
      .attr('height', newSummaryHeight - paddingT * 2)
      .select('p')
      .style('font-size', topicSizeOptions.fontSize + 'px')
      .style('font-family', topicSizeOptions.fontFamily)
    summaryNode.select('.summary-line-path')
      .html(() => {
        const path = horizontal ? summaryLineShape[topicSizeOptions.lineShape].horizontal({ x: startX, y: minY }, { x: startX, y: maxY }, direction)
          : summaryLineShape[topicSizeOptions.lineShape].vertical({ x: minX, y: startY }, { x: maxX, y: startY }, direction)
        const n = rc.path(path, {
          fill: 'none',
          stroke: style.lineColor,
          strokeWidth: 2,
          ...(topicSizeOptions.isRough ? summaryRoughOptions : summaryNoRoughOptions)
        })
        return select(n).html()
      })
    summaryNode.select('.summary-topic-path')
      .html(() => {
        const generateShapePath = topicShape[topicSizeOptions.shape].generateShapePath
        const path = generateShapePath(newRectX, newRectY, newSummaryWidth, newSummaryHeight)
        const n = rc.path(path, {
          fill: style.topicFill,
          stroke: style.topicStrokeColor,
          strokeWidth: 2,
          ...(topicSizeOptions.isRough ? summaryRoughOptions : summaryNoRoughOptions)
        })
        return select(n).html()
      })
    summaryNode.select('.summary-highlight-border')
      .attr('x', () => {
        return horizontal
          ? centerPosition.x + (highLightTopicSpacing * 2 - highLightSummarySpacing) * unit - (forwardDirection ? 0 : newSummaryWidth + highLightSummarySpacing * 2)
          : centerPosition.x - newSummaryWidth / 2 - highLightSummarySpacing
      })
      .attr('y', () => {
        return horizontal
          ? centerPosition.y - newSummaryHeight / 2 - highLightSummarySpacing
          : centerPosition.y + (highLightTopicSpacing * 2 - highLightSummarySpacing) * unit - (forwardDirection ? 0 : newSummaryHeight + highLightSummarySpacing * 2)
      })
      .attr('width', newSummaryWidth + highLightSummarySpacing * 2)
      .attr('height', newSummaryHeight + highLightSummarySpacing * 2)
    currentSummarydata.rectX = newRectX
    currentSummarydata.rectY = newRectY
    currentSummarydata.summaryWidth = newSummaryWidth
    currentSummarydata.summaryHeight = newSummaryHeight
    currentSummarydata.paddingLR = paddingL
    currentSummarydata.paddingTB = paddingT
  }
  debounceUpdateData(styleName, styleValue, root, callback)
}

/**
 * 防抖更新数据
 */
const debounceUpdateData = debounce((styleName, styleValue, root, callback) => {
  const ids = selectCombinationId.split('-')
  const [sId, tId] = [ids[0], ids[1]]
  const target = getTargetDataById(root, sId)
  const summary = target.targetSummarys.find(o => o.id === tId)
  summary.style = {
    ...summary.style,
    [styleName]: styleValue
  }
  currentSummarydata.style[styleName] = styleValue
  callback && callback()
}, 300)

/**
 * 概要整体节点样式更新
 * @param {*} root
 * @param {*} style
 * @param {*} callback
 */
export function updateSummaryFullStyle (root, style, callback) {
  const ids = selectCombinationId.split('-')
  const [sId, tId] = [ids[0], ids[1]]
  const target = getTargetDataById(root, sId)
  const summary = target.targetSummarys.find(o => o.id === tId)
  summary.style = style
  currentSummarydata.style = style
  callback && callback()
}
